#include <iostream>
#include <vector>
#include <queue>
#include <chrono>
#include <filesystem>
#include <thread>
#include "quality_evaluation.hpp"

#define NUM_THREADS 20

/**
 * 读取并处理指定路径下的图像文件。
 * 
 * @param path 图像文件所在的目录路径。
 * @param img_info 用于存储图像信息的向量。
 * 
 */
void read_and_process(const std::string& path, std::vector<imageInfo>& img_info) {
    // 判断路径是否存在
    if (!std::filesystem::exists(path)) {
        std::cerr << "Path does not exist: " << path << std::endl;
        return;
    }
    // 判断路径是否为目录
    if (!std::filesystem::is_directory(path)) {
        std::cerr << "Path is not a directory: " << path << std::endl;
        return;
    }
    try {
        // 遍历指定目录下的所有文件
        for (const auto & entry : std::filesystem::directory_iterator(path)) {
            // 临时变量，用于存储单个图像的路径和id
            imageInfo img_info_temp;
            // 获取图像文件的完整路径
            std::string img_path = entry.path().string();
            
            // 获取img_id: 假设文件名格式为 "*****_12.5.bmp"
            // index_start 和 index_end 分别存储文件名中"."和"_"的位置
            size_t index_start = img_path.find_last_of(".");
            size_t index_end = img_path.find("_");

            // 如果找到了文件名中的"_"和"."，则提取img_id
            if (index_start != std::string::npos && index_end != std::string::npos) {

                // 提取并存储img_id
                std::string img_id = img_path.substr(index_end + 1, index_start - index_end - 1);

                // 将图像路径和id存储到临时变量中
                img_info_temp.img_path = img_path;
                img_info_temp.img_id = img_id;
                
                // 将临时变量添加到图像信息向量中
                img_info.push_back(img_info_temp);
            }
        }
    } catch (const std::exception& e) {
        // 异常处理: 捕获并输出异常信息
        std::cerr << "Error during directory iteration: " << e.what() << std::endl;
    }
}

/**
 * 计算给定范围内图像的质量分数。
 * 
 * @param img_info 图像信息的向量，包含图像路径和分数等信息。
 * @param startIdx 计算分数的起始索引。
 * @param endIdx 计算分数的结束索引（不包含）。
 * 
 */
void calculate_score(std::vector<imageInfo>& img_info, int startIdx, int endIdx) {
    // 检查边界条件
    if (startIdx < 0 || endIdx > static_cast<int>(img_info.size()) || startIdx >= endIdx) {
        throw std::out_of_range("Invalid index range");
    }

    // 遍历指定范围内的图像
    for (int i = startIdx; i < endIdx; i++) {
        try {
            // 读取图像
            cv::Mat img = cv::imread(img_info[i].img_path);
            // 检查图像是否成功加载
            if (img.empty()) {
                throw std::runtime_error("Failed to load image: " + img_info[i].img_path);
            }
            
            // 裁剪图像，调整大小
            qe::cropImage(img, img, 0.25);
            // 计算图像的质量分数
            double smd2_score = qe::getQuality(img, qe::QualityEvaluationType::SMD2);
            // 将分数保存到图像信息中
            img_info[i].score = smd2_score;
        } catch (const cv::Exception& e) {
            // 处理 OpenCV 异常
            std::cerr << "OpenCV exception: " << e.what() << std::endl;
        } catch (const std::exception& e) {
            // 处理其他标准库异常
            std::cerr << "Exception: " << e.what() << std::endl;
        }
    }
}

int main(int argc, char** argv) {
    // 初始化计时器，用于测量整个评估过程的耗时
    calculate_time t1("Image Quality Evaluation");
    
    // 获取图像路径，从命令行参数中获取
    std::string img_path = argv[1];

    // 初始化图像信息存储容器
    std::vector<imageInfo> img_info;

    // 读取并处理图像，将相关信息存储到img_info中
    read_and_process(img_path, img_info);
    
    // 计算图像数量
    int image_num = img_info.size();
    std::cout << "image_num: " << image_num << std::endl;
    std::cout << "thread_num: " << NUM_THREADS << std::endl;
    // 初始化线程容器，用于并行计算
    std::vector<std::thread> threads(NUM_THREADS);
    // 计算采样间隔
    int interval = image_num / NUM_THREADS;

    // 创建并启动线程，分配图像计算任务
    for (size_t i = 0; i < NUM_THREADS; i++){
        // 计算每个线程处理的起始和结束索引
        int startIdx = i * interval;
        int endIdx = (i == NUM_THREADS - 1) ? image_num : (i + 1) * interval;
        // 输出调试信息，显示每个线程处理的图像索引范围
        // std::cout << "startIdx: " << startIdx << " endIdx: " << endIdx << std::endl;
        // 创建并启动线程，传递图像信息和处理范围
        threads[i] = std::thread(calculate_score, std::ref(img_info), startIdx, endIdx);
    }

    // 等待所有线程执行完毕
    for (auto& thread : threads) {
        thread.join();
    }

    // 查找图像中最高分数
    // auto max_image = std::max_element(img_info.begin(), img_info.end(), [](const imageInfo& a, const imageInfo& b) {
    //     return a.score < b.score;
    // });
    // 输出最高分数的图像ID和分数
    // std::cout << "max image id: " << max_image->img_id << " score: " << max_image->score << std::endl;

    // 将图像信息按分数降序排序
    std::sort(img_info.begin(), img_info.end(), [](const imageInfo& a, const imageInfo& b) {
        return a.score > b.score;
    });

    // 输出最高分数的图像ID和分数
    std::cout << "max image id: " << img_info[0].img_id << " score: " << img_info[0].score << std::endl;

    // 输出到txt文件
    qe::write_to_txt(img_info, "result.txt");
    // 输出整个评估过程的耗时
    t1.print_time();

    return 0;

}
